package p.a4;

/*
 +---+---+---+---+---+---+---+---+
 | 1 | 2 | 3 | 4 | 1 | 2 | 3 | 4 |
 +---+---+---+---+---+---+---+---+
 | 3 | 4 | 1 | 2 | 3 | 4 | 1 | 2 |
 +---+---+---+---+---+---+---+---+
 | 1 | 2 | 3 | 4 | 1 | 2 | 3 | 4 |
 +---+---+---+---+---+---+---+---+
 | 3 | 4 | 1 | 2 | 3 | 4 | 1 | 2 |
 +---+---+---+---+---+---+---+---+
 | 1 | 2 | 3 | 4 | 1 | 2 | 3 | 4 |
 +---+---+---+---+---+---+---+---+
 | 3 | 4 | 1 | 2 | 3 | 4 | 1 | 2 |
 +---+---+---+---+---+---+---+---+
 | 1 | 2 | 3 | 4 | 1 | 2 | 3 | 4 |
 +---+---+---+---+---+---+---+---+
 | 3 | 4 | 1 | 2 | 3 | 4 | 1 | 2 |
 +---+---+---+---+---+---+---+---+


 +---+---+---+---+---+---+---+---+
 |   |   |   |   |   |   |   |   |
 +---+---+---+---+---+---+---+---+
 |   |   | x |   | X |   |   |   |
 +---+---+---+---+---+---+---+---+
 |   | x |   |   |   | x |   |   |
 +---+---+---+---+---+---+---+---+
 |   |   |   | K |   |   |   |   |
 +---+---+---+---+---+---+---+---+
 |   | x |   |   |   | x |   |   |
 +---+---+---+---+---+---+---+---+
 |   |   | x |   | x |   |   |   |
 +---+---+---+---+---+---+---+---+
 |   |   |   |   |   |   |   |   |
 +---+---+---+---+---+---+---+---+
 |   |   |   |   |   |   |   |   |
 +---+---+---+---+---+---+---+---+






 */

public class Springer {

	static int Debug = 0; // 0 off 1 program 2 recursion
	static long depth = 0;
	static int N = 0;
	static int knights = 0;
	static int maxknights = 0;
	static int knight[][];
	static int avail[][];

	private static int nextFree(int x, int y) {
		int result = 0;
		for (int yy = y; yy < N; yy++) {
			for (int xx = x; xx < N; xx++) {
				if ((knight[xx][yy] == 0) && (avail[xx][yy] == 0)) {
					// && (avail[x][y] == 0)
					if (Debug == 1) {
						System.out.print(" nextfree: (" + xx + "/" + yy + ")");
					}
					result = (xx * N) + yy;
					break;
				}
			}
			if (result != 0) {
				break;
			}
		}
		return result;
	}

	private static int[][] newArray(int len, int initVal) {
		// create pre-initialized boolean-array of length 'len'
		int[][] a = new int[len][len];
		for (int i = 0; i < len; i++) {
			for (int j = 0; j < len; j++) {
				a[i][j] = initVal;
			}
		}
		return a;
	}

	public static void main(String[] args) {
		// initialization
		N = 8;
		knights = 0;
		avail = newArray(N, 0);
		knight = newArray(N, 0);

		// start search for solution
		tryknight(0, 0);
		System.out.println("FIN.");

	}

	private static boolean inField(int x, int y) {
		if (Debug == 1) {
			// System.out.println(x + " " + y);
		}
		if ((x > (N - 1)) || (x < 0) || (y > (N - 1)) || (y < 0)) {
			return false;
		} else {
			return true;
		}
	}

	private static boolean isPromising(int x, int y) {

		boolean result = true;

		if (inField(x, y)) {
			// field occupied?
			if (knight[x][y] > 0) {
				result = false;
			}

			// field in strike range?
			if (avail[x][y] > 0) {
				result = false;
			}
		} else {
			// field unavailable
			result = false;
		}
		return result;

	}

	// try to put a knight into (x,y)
	private static void tryknight(int x, int y) {
		if (Debug == 2) {
			System.out.print("\n depth: (" + depth + ") begin (" + knights + "/" + maxknights + "): (" + x + "/" + y + ")");
		}

		// try all following kombinations
		for (int yy = y; yy < N; yy++) {
			for (int xx = x; xx < N; xx++) {
				if (Debug == 2) {
					System.out.print(" check: (" + xx + "/" + yy + ")");
				}
				// looks good?
				if (isPromising(xx, yy)) {

					// put knight on board
					if (Debug == 1) {
						System.out.print("\n put knight in field: (" + xx + "/" + yy + ")");
					}
					if (Debug == 2) {
						depth++;
						// System.out.print(" depth: (" + depth + ")");
					}
					knights++;
					putknight(knights, xx, yy);

					// find next free space
					int i, j, n = 0;
					n = nextFree(xx, yy);
					if (Debug == 1) {
						// System.out.print(" converted to " + n);
					}
					if (n == 0) {
						// no free field
						if (Debug == 1) {
							System.out.print(" no free space anymore. ");
						}
						// new maximum?
						if (knights > maxknights) {
							if (Debug == 1) {
								System.out.print(" NEW MAX! ");
							}
							maxknights = knights;
							printSolution();
						}

					} else {
						j = n % N;
						i = n / N;
						if (Debug == 1) {
							// System.out.print(" converts back to (" + i + "/"
							// + j +
							// ")");
						}
						tryknight(i, j);
					}

					// remove knight
					if (Debug == 2) {
						depth--;
						System.out.print("\n depth: (" + depth + ") remove: (" + xx + "/" + yy + ")");
					}
					putknight(-knights, xx, yy);
					knights--;

				} else {
					if (Debug == 1) {
						// System.out.print(" is not promising! ");
					}
				}
			}
		}
	}

	private static void putknight(int k, int x, int y) {
		/*
		 * if (k < 0) { knights--; } else { knights++; }
		 */
		knight[x][y] = knight[x][y] + k;

		int strikex = 0;
		int strikey = 0;

		strikex = x + 2;
		strikey = y + 1;
		if (inField(strikex, strikey) == true) {
			avail[strikex][strikey] = avail[strikex][strikey] + k;
		}
		strikex = x + 2;
		strikey = y - 1;
		if (inField(strikex, strikey) == true) {
			avail[strikex][strikey] = avail[strikex][strikey] + k;
		}
		strikex = x - 2;
		strikey = y + 1;
		if (inField(strikex, strikey) == true) {
			avail[strikex][strikey] = avail[strikex][strikey] + k;
		}
		strikex = x - 2;
		strikey = y - 1;
		if (inField(strikex, strikey) == true) {
			avail[strikex][strikey] = avail[strikex][strikey] + k;
		}
		strikex = x + 1;
		strikey = y + 2;
		if (inField(strikex, strikey) == true) {
			avail[strikex][strikey] = avail[strikex][strikey] + k;
		}
		strikex = x + 1;
		strikey = y - 2;
		if (inField(strikex, strikey) == true) {
			avail[strikex][strikey] = avail[strikex][strikey] + k;
		}
		strikex = x - 1;
		strikey = y + 2;
		if (inField(strikex, strikey) == true) {
			avail[strikex][strikey] = avail[strikex][strikey] + k;
		}
		strikex = x - 1;
		strikey = y - 2;
		if (inField(strikex, strikey) == true) {
			avail[strikex][strikey] = avail[strikex][strikey] + k;
		}
	}

	private static void printSolution() {
		System.out.println("");
		System.out.println("solution found with " + knights + " knights:");
		for (int y = 0; y < N; y++) {
			for (int x = 0; x < N; x++) {
				if (knight[x][y] > 0) {
					System.out.print("K");
				} else {
					System.out.print("*");
				}
			}
			System.out.println("");
		}

	}
}
